using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WPCoco.Tasks
{
    public class TimeSequence : FiniteTime, IContainer<Task>
    {
        public TimeSequence(params FiniteTime[] tasks)
            : base(0)
        {
            this.tasks = tasks;
            timeline = new float[tasks.Length];
            durations = new float[tasks.Length];
            initialized = new bool[tasks.Length];
            UpdateTimeLine();
        }

        FiniteTime[] tasks;
        float[] timeline;
        float[] durations;
        bool[] initialized;
        int index;

        void UpdateTimeLine() 
        {
            durations[0] = timeline[0] = tasks[0].Duration;
            tasks[0].StartTime = 0;
            for (int i = 1; i < tasks.Length; i++)
            {
                durations[i] = tasks[i].Duration;
                timeline[i] = timeline[i - 1] + tasks[i].Duration;
                tasks[i].StartTime = timeline[i - 1];
                initialized[i] = false;
            }
            Duration = timeline[tasks.Length - 1];
        }

        public override void Initialize()
        {
            base.Initialize();
            UpdateTimeLine();
            index = 0;
            initialized[0] = true;
            tasks[0].Initialize();
        }

        public override void Update(float time)
        {
            base.Update(time);
            int last = index;
            while (time > timeline[index])
            {
                if (index == timeline.Length - 1) break;
                index++;
            }
            while (time < timeline[index] - durations[index])
            {
                if (index == 0) break;
                index--;
            }
            if (index != last) 
            {
                int k = last;
                while (k != index)
                {
                    if (!initialized[k])
                    {
                        initialized[k] = true;
                        tasks[k].Initialize();
                    }
                    if (index < last)
                    {
                        tasks[k].Update(0);
                        k--;
                    }
                    else
                    {
                        tasks[k].Update(durations[k]);
                        k++;
                    }
                }
            }
            if (!initialized[index])
            {
                initialized[index] = true;
                tasks[index].Initialize();
            }
            tasks[index].Update(time - tasks[index].StartTime);    
        }

        public override Task Clone()
        {
            FiniteTime[] innerCloned = new FiniteTime[tasks.Length];
            for (int i = 0; i < tasks.Length; i++)
                innerCloned[i] = tasks[i].Clone() as FiniteTime;
            TimeSequence task = new TimeSequence(innerCloned);
            return task;
        }

        public override Task Reverse()
        {
            FiniteTime[] innerCloned = new FiniteTime[tasks.Length];
            for (int i = 0; i < tasks.Length; i++)
                innerCloned[i] = tasks[tasks.Length - i - 1].Reverse() as FiniteTime;
            Sequence task = new Sequence(innerCloned);
            return task;
        }

        #region IContainer<Task> Members

        public IEnumerable<Task> GetContainerEnumerator()
        {
            for (int i = 0; i < tasks.Length; i++)
                yield return tasks[i];
            yield break;
        }

        #endregion
    }
}
